#include <assert.h>
#include <stdio.h>

#include "../src/distribution.c"
#include "../src/qfunc.c"

typedef struct _LogPRatingTestDatum LogPRatingTestDatum ;
struct _LogPRatingTestDatum 
{ 
  struct
    {
      unsigned int      rating;
      double            alpha[4];
      double            logbeta;
    }                                   inputs;
  double                                desired_output;
};

static void
test_logprating (void)
{
  LogPRatingTestDatum data[] = 
    {{{3, {0.833249, 0.965062, 0.0882295, 0.148109}, 0.254743}, -1.04452}, {{2, {0.695449, 0.488398, 0.97021, 0.32168}, 0.664682}, -2.17304}, {{1, {0.228919, 0.708024, 0.889281, 0.512718}, 0.0933638}, -1.55832}, {{0, {0.138158, 0.925201, 0.375761, 0.949392}, 0.257005}, -0.894948}, {{0, {0.958452, 0.437078, 0.964528, 0.0474854}, 0.125202}, -1.88809}, {{3, {0.472016, 0.876298, 0.899376, 0.870459}, 0.776567}, -1.66853}, {{1, {0.387901, 0.929165, 0.54878, 0.111885}, 0.158982}, -1.95372}, {{1, {0.221142, 0.659499, 0.599167, 0.0656183}, 0.0829836}, -1.71996}, {{2, {0.734297, 0.223406, 0.116226, 0.825978}, 0.775846}, -0.81863}, {{2, {0.786328, 0.151698, 0.778493, 0.650643}, 0.314312}, -1.71195}};

  for (unsigned int i = 0; i < sizeof (data) / sizeof (data[0]); ++i)
    {
      auto double alphafunc (unsigned int);
      double alphafunc (unsigned int x) { return data[i].inputs.alpha[x]; }
      double output = logprating (data[i].inputs.rating,
                                  alphafunc,
                                  data[i].inputs.logbeta,
                                  4);

      assert (fabs (output - data[i].desired_output) <=
              1e-5 * (1 + fabs (output) + fabs (data[i].desired_output)) ||
              ( fprintf (stderr, "%g ?= %g\n", output, data[i].desired_output),
                0 ));
    }
}

static void
test_dlogpratingdlogbeta (void)
{
  LogPRatingTestDatum data[] = 
    {{{3, {0.143241, 0.30918, 0.782666, 0.0217101}, 0.652013}, 0.323664}, {{1, {0.00659769, 0.448854, 0.116555, 0.737362}, 0.89627}, -0.699752}, {{3, {0.407064, 0.279119, 0.750552, 0.566001}, 0.417876}, -0.168126}, {{0, {0.108287, 0.395321, 0.41825, 0.798068}, 0.799897}, 0.45165}, {{0, {0.336108, 0.477524, 0.00174119, 0.39439}, 0.192867}, -0.0931007}, {{2, {0.168344, 0.219075, 0.37268, 0.540854}, 0.161746}, -0.0837997}, {{3, {0.77022, 0.256125, 0.803492, 0.265476}, 0.363157}, 0.234722}, {{0, {0.977006, 0.0529402, 0.699475, 0.945281}, 0.868719}, -1.63011}, {{1, {0.657619, 0.281225, 0.147213, 0.0688215}, 0.321511}, -0.073969}, {{1, {0.803702, 0.145472, 0.674431, 0.128644}, 0.635358}, 0.257961}};

  for (unsigned int i = 0; i < sizeof (data) / sizeof (data[0]); ++i)
    {
      auto double alphafunc (unsigned int);
      double alphafunc (unsigned int x) { return data[i].inputs.alpha[x]; }

      double output = dlogpratingdlogbeta (data[i].inputs.rating,
                                           alphafunc,
                                           data[i].inputs.logbeta,
                                           4);

      assert (fabs (output - data[i].desired_output) <=
              1e-5 * (1 + fabs (output) + fabs (data[i].desired_output)) ||
              ( fprintf (stderr, "%g ?= %g\n", output, data[i].desired_output),
                0 ));
    }
}

typedef struct _DLogPRatingDalphaTestDatum DLogPRatingDalphaTestDatum;
struct _DLogPRatingDalphaTestDatum 
{
  struct
    {
      unsigned int      rating;
      double            alpha[4];
      double            logbeta;
    }                                   inputs;

  double                                desired_output[4];
};

static void
test_dlogpratingdalpha (void)
{
  DLogPRatingDalphaTestDatum data[] = 
    {{{1, {0.898961, 0.398726, 0.840596, 0.0715633}, 0.306289}, {0.190454, -0.982627, 0.206168, 0.586005}}, {{0, {0.65612, 0.44234, 0.512317, 0.128452}, 0.710759}, {-1.73675, 0.461693, 0.400398, 0.874655}}, {{3, {0.686444, 0.499408, 0.45617, 0.786126}, 0.293408}, {0.296566, 0.381108, 0.403858, -1.08153}}, {{2, {0.413459, 0.512822, 0.322883, 0.492526}, 0.485475}, {0.417843, 0.355543, -1.14085, 0.367464}}, {{3, {0.100536, 0.796945, 0.122953, 0.327046}, 0.201575}, {0.387433, 0.165274, 0.376953, -0.929661}}, {{1, {0.398219, 0.282357, 0.255483, 0.895286}, 0.742099}, {0.528104, -1.42674, 0.712719, 0.185914}}, {{1, {0.840017, 0.743166, 0.766834, 0.0313401}, 0.153574}, {0.201866, -0.939994, 0.219848, 0.51828}}, {{3, {0.243758, 0.310664, 0.245215, 0.860165}, 0.830298}, {0.740589, 0.635215, 0.738118, -2.11392}}, {{0, {0.797842, 0.922331, 0.36764, 0.344823}, 0.697306}, {-1.70566, 0.235721, 0.718132, 0.751806}}, {{0, {0.125387, 0.244686, 0.017777, 0.495731}, 0.727167}, {-1.47723, 0.46249, 0.739629, 0.275107}}};

  for (unsigned int i = 0; i < sizeof (data) / sizeof (data[0]); ++i)
    {
      auto double alphafunc (unsigned int);
      double alphafunc (unsigned int x) { return data[i].inputs.alpha[x]; }
      double dalpha[4];

      memset (dalpha, lrand48 (), 4 * sizeof (dalpha[0]));

      dlogpratingdalpha (dalpha,
                         data[i].inputs.rating,
                         alphafunc,
                         data[i].inputs.logbeta,
                         4);

      for (unsigned int j = 0; j < 4; ++j)
        {
          assert (fabs (dalpha[j] - data[i].desired_output[j]) <=
                  1e-5 * (1 + fabs (dalpha[j]) + fabs (data[i].desired_output[j])) ||
                  ( fprintf (stderr, "%g ?= %g\n", dalpha[j], data[i].desired_output[j]),
                    0 ));
        }
    }
}

typedef struct _NormalDistributionTestDatum NormalDistributionTestDatum;
struct _NormalDistributionTestDatum 
{
  double mean;
  double stddev;
  double x;
  double desired_output;
  double desired_doutput;
};

static void
test_normaldistribution (void)
{
  NormalDistributionTestDatum data[] = 
    {{0.926397, 0.301751, 0.58779, -0.350384, 3.71875}, {0.473612, 0.156177, 0.0456262, -2.81705, 17.5467}, {0.784299, 0.208136, 0.79302, 0.649749, -0.201327}, {0.0686202, 0.731358, 0.50866, -0.787093, -0.822682}, {0.847739, 0.199902, 0.073739, -6.80483, 19.369}, {0.227435, 0.700526, 0.13108, -0.572474, 0.196347}, {0.752228, 0.423733, 0.555054, -0.168552, 1.09816}, {0.456649, 0.623583, 0.788376, -0.588161, -0.853083}, {0.628656, 0.154897, 0.0357929, -6.37867, 24.7096}, {0.314764, 0.47248, 0.109271, -0.263757, 0.920512}};

  for (unsigned int i = 0; i < sizeof (data) / sizeof (data[0]); ++i)
    {
      NormalDistribution p = normal_distribution (data[i].mean, data[i].stddev);

      double output = p.base.logpdf (data[i].x, &p);
      double doutput = p.base.dlogpdf (data[i].x, &p);

      assert (fabs (output - data[i].desired_output) <=
              1e-5 * (1 + fabs (output) + fabs (data[i].desired_output)) ||
              ( fprintf (stderr, "%g ?= %g\n", output, data[i].desired_output),
                0 ));

      assert (fabs (doutput - data[i].desired_doutput) <=
              1e-5 * (1 + fabs (doutput) + fabs (data[i].desired_doutput)) ||
              ( fprintf (stderr, "%g ?= %g\n", doutput, data[i].desired_doutput),
                0 ));
    }
}
        

typedef struct _QFuncTestDatum QFuncTestDatum ;
struct _QFuncTestDatum 
{ 
  struct
    {
      double    alpha[4 * 5 * 5];
      double    logbeta[3];
      double    pz[3 * 5];
      double    priorz[5];
      Rating    ratings[8];
      double    alphamean;
      double    alphastddev;
      double    logbetamean;
      double    logbetastddev;
    }                   inputs;
  double                desired_output;
};

static void
test_qfunc (void)
{
  QFuncTestDatum data[] = 
    {{{{0, 0.61867, 0.212652, 0.922094, 0.840275, 0.732927, 0, 0.251549,  0.39076, 0.407395, 0.628547, 0.214929, 0, 0.00493253, 0.0817617,  0.462577, 0.856444, 0.817181, 0, 0.348957, 0.204152, 0.172152,  0.405214, 0.302537, 0, 0, 0.803063, 0.511252, 0.586466, 0.939127,  0.184394, 0, 0.2986, 0.664373, 0.0988517, 0.451467, 0.0470509, 0,  0.273612, 0.691456, 0.82292, 0.832122, 0.26868, 0, 0.609695,  0.360343, 0.975678, 0.451499, 0.260737, 0, 0, 0.156191, 0.803526,  0.0462851, 0.958201, 0.353127, 0, 0.292274, 0.459819, 0.0190735,  0.168734, 0.993674, 0, 0.795446, 0.920222, 0.717267, 0.946623,  0.521834, 0, 0.228765, 0.894347, 0.114502, 0.253154, 0.619071, 0,  0, 0.534005, 0.138824, 0.801654, 0.358334, 0.377814, 0, 0.335298,  0.755369, 0.400133, 0.0246864, 0.043024, 0, 0.29555, 0.381059,  0.855953, 0.04935, 0.500104, 0, 0.460838, 0.138685, 0.102727,  0.97827, 0.232072, 0}, {0.244338, 0.988225, 0.725117}, {0.613001,  0.710333, 0.849402, 0.923462, 0.254668, 0.332519, 0.514104,  0.168093, 0.854535, 0.307833, 0.47108, 0.872542, 0.473475,  0.45188, 0.42173}, {0.372438, 0.0126375, 0.313195, 0.319003,  0.394168}, {{2, 2, 4}, {1, 2, 4}, {0, 1, 4}, {0, 0, 4}, {2, 1,  3}, {3, 2, 0}, {2, 2, 4}, {3, 2, 4}}, 0.780565, 0.0688573,  0.330777,  0.669051}, -2747.7}, {{{0, 0.167564, 0.358524, 0.481376, 0.745589,  0.912896, 0, 0.0260049, 0.967272, 0.577496, 0.0583616, 0.718172,  0, 0.496193, 0.704954, 0.584886, 0.266292, 0.0744629, 0, 0.332516,  0.572249, 0.953097, 0.75546, 0.938348, 0, 0, 0.791684, 0.884239,  0.424683, 0.269297, 0.62412, 0, 0.525715, 0.943307, 0.523708,  0.711223, 0.49971, 0, 0.976035, 0.946212, 0.652862, 0.781538,  0.479842, 0, 0.241258, 0.0679755, 0.515246, 0.405379, 0.908742, 0,  0, 0.495727, 0.56215, 0.649919, 0.970394, 0.704043, 0, 0.67791,  0.225236, 0.701097, 0.0799234, 0.152195, 0, 0.28193, 0.177389,  0.3687, 0.652485, 0.305895, 0, 0.231177, 0.715838, 0.870947,  0.826053, 0.989919, 0, 0, 0.647863, 0.3557, 0.420673, 0.0811765,  0.152136, 0, 0.793551, 0.770754, 0.110782, 0.448093, 0.11564, 0,  0.545518, 0.409686, 0.36817, 0.963445, 0.263588, 0, 0.232297,  0.99947, 0.31096, 0.957693, 0.00112016, 0}, {0.283631, 0.440014,  0.131641}, {0.0112015, 0.635768, 0.0843132, 0.710968, 0.930025,  0.483632, 0.290763, 0.940214, 0.819243, 0.0355392, 0.175122,  0.394696, 0.409557, 0.66737, 0.211677}, {0.131108, 0.17726,  0.6679, 0.900717,  0.173414}, {{2, 0, 0}, {1, 1, 4}, {1, 2, 2}, {3, 2, 3}, {2, 0,  3}, {1, 0, 1}, {2, 1, 2}, {0, 1, 2}}, 0.17614, 0.384269,  0.460703,  0.0417736}, -125.538}, {{{0, 0.164938, 0.7485, 0.37639, 0.330806,  0.234913, 0, 0.264868, 0.0856274, 0.390592, 0.415671, 0.229329, 0,  0.910505, 0.995897, 0.00611401, 0.561959, 0.698828, 0, 0.864789,  0.828854, 0.894059, 0.798111, 0.691374, 0, 0, 0.652714, 0.509791,  0.337408, 0.649601, 0.487776, 0, 0.76129, 0.961018, 0.318795,  0.252862, 0.496422, 0, 0.875391, 0.928202, 0.837191, 0.267094,  0.964886, 0, 0.932306, 0.831077, 0.705134, 0.266057, 0.067517, 0,  0, 0.00222342, 0.811075, 0.467946, 0.376143, 0.349509, 0,  0.301284, 0.130538, 0.726542, 0.861733, 0.539994, 0, 0.16952,  0.407747, 0.608871, 0.0435712, 0.294129, 0, 0.479544, 0.77168,  0.776478, 0.329243, 0.547238, 0, 0, 0.940602, 0.0713435,  0.0631858, 0.479721, 0.938379, 0, 0.260269, 0.59524, 0.103579,  0.58887, 0.958985, 0, 0.464702, 0.377037, 0.727136, 0.418991,  0.295182, 0, 0.969291, 0.118265, 0.37542, 0.00105332, 0.489746,  0}, {0.346585, 0.598942, 0.67181}, {0.942508, 0.405983, 0.527599,  0.608624, 0.462786, 0.467604, 0.26733, 0.0133845, 0.359207,  0.878734, 0.308345, 0.548683, 0.98217, 0.151598,  0.889354}, {0.2535, 0.0128797, 0.0333334, 0.513934,  0.252447}, {{3, 1, 4}, {3, 1, 4}, {0, 2, 3}, {1, 1, 0}, {3, 0,  3}, {3, 1, 4}, {3, 0, 4}, {0, 2, 0}}, 0.523133, 0.686748,  0.914992,  0.580637}, -121.103}, {{{0, 0.580626, 0.280765, 0.387393, 0.972013,  0.117839, 0, 0.813161, 0.120063, 0.958628, 0.758632, 0.934427, 0,  0.811717, 0.409946, 0.776462, 0.782828, 0.922363, 0, 0.156445,  0.763582, 0.749495, 0.408429, 0.903998, 0, 0, 0.240448, 0.0627468,  0.493437, 0.323361, 0.659823, 0, 0.781982, 0.106045, 0.351348,  0.541984, 0.968821, 0, 0.985982, 0.39272, 0.783352, 0.034394,  0.174265, 0, 0.982774, 0.00688999, 0.251566, 0.251901, 0.826329,  0, 0, 0.243308, 0.502071, 0.843472, 0.922331, 0.00285952, 0,  0.439324, 0.350035, 0.59897, 0.343037, 0.657342, 0, 0.24399,  0.247621, 0.801053, 0.688522, 0.258009, 0, 0.854901, 0.0177016,  0.654128, 0.0837439, 0.872127, 0, 0, 0.0108116, 0.402562,  0.831842, 0.0457983, 0.767504, 0, 0.900491, 0.98837, 0.123468,  0.764644, 0.461167, 0, 0.638335, 0.524498, 0.421607, 0.803825,  0.394344, 0, 0.276877, 0.620554, 0.115304, 0.136336, 0.421975,  0}, {0.602853, 0.461176, 0.052592}, {0.549848, 0.592041,  0.0586139, 0.22075, 0.50405, 0.824537, 0.158123, 0.23238,  0.380582, 0.0598934, 0.696955, 0.594045, 0.856084, 0.638286,  0.89313}, {0.1997, 0.579208, 0.017732, 0.777826,  0.0633642}, {{0, 2, 1}, {3, 0, 1}, {2, 2, 1}, {2, 1, 0}, {3, 1,  0}, {2, 2, 3}, {3, 0, 3}, {0, 1, 1}}, 0.157233, 0.414879,  0.316651,  0.0107722}, -837.577}, {{{0, 0.607385, 0.822838, 0.258037,  0.790023, 0.103335, 0, 0.998301, 0.0999141, 0.557643, 0.722753,  0.938408, 0, 0.402959, 0.963598, 0.866668, 0.300121, 0.509829, 0,  0.763898, 0.287461, 0.282389, 0.732003, 0.700534, 0, 0, 0.130228,  0.86751, 0.415352, 0.689762, 0.522844, 0, 0.0446717, 0.157315,  0.899739, 0.419509, 0.0463707, 0, 0.0574013, 0.342096, 0.696756,  0.107963, 0.654442, 0, 0.378498, 0.830087, 0.807842, 0.144613,  0.6146, 0, 0, 0.542627, 0.525452, 0.412611, 0.914065, 0.412399, 0,  0.657942, 0.997259, 0.224304, 0.889555, 0.613271, 0, 0.839944,  0.324564, 0.470046, 0.5669, 0.782542, 0, 0.982468, 0.77329,  0.458937, 0.1281, 0.60397, 0, 0, 0.943203, 0.651095, 0.983486,  0.989371, 0.400576, 0, 0.125643, 0.570875, 0.0753052, 0.988178,  0.4677, 0, 0.573617, 0.851002, 0.0986228, 0.85443, 0.733673, 0,  0.526437, 0.628576, 0.28753, 0.951131, 0.543969, 0}, {0.855286,  0.828593, 0.823031}, {0.939999, 0.912083, 0.177498, 0.839545,  0.950628, 0.511507, 0.0518555, 0.268669, 0.875323, 0.523329,  0.584155, 0.695053, 0.0243216, 0.424706, 0.729725}, {0.96138,  0.497884, 0.79613, 0.442196,  0.0102489}, {{2, 2, 1}, {1, 0, 0}, {2, 1, 3}, {3, 1, 0}, {2, 0,  0}, {1, 0, 3}, {2, 2, 1}, {1, 0, 2}}, 0.953915, 0.940844,  0.613602,  0.187218}, -163.211}, {{{0, 0.0139158, 0.0287607, 0.436104,  0.347673, 0.0632874, 0, 0.517254, 0.384249, 0.0790043, 0.187964,  0.993925, 0, 0.800094, 0.383952, 0.163643, 0.569219, 0.0703681, 0,  0.422572, 0.665758, 0.773089, 0.628173, 0.412323, 0, 0, 0.711843,  0.832246, 0.0145701, 0.225105, 0.697928, 0, 0.803485, 0.578466,  0.877432, 0.63464, 0.286231, 0, 0.194217, 0.798427, 0.446676,  0.292306, 0.394123, 0, 0.414476, 0.283033, 0.723087, 0.323755,  0.991904, 0, 0, 0.617275, 0.949998, 0.695583, 0.579581, 0.905431,  0, 0.117752, 0.681013, 0.354475, 0.207504, 0.314267, 0, 0.102547,  0.477044, 0.572864, 0.0280358, 0.90833, 0, 0.678616, 0.126188,  0.73573, 0.514206, 0.264141, 0, 0, 0.843154, 0.0126431, 0.190451,  0.272237, 0.225879, 0, 0.0626456, 0.494868, 0.692656, 0.320448,  0.944894, 0, 0.813856, 0.338181, 0.112944, 0.630627, 0.711309, 0,  0.861137, 0.54008, 0.602591, 0.802979, 0.182521, 0}, {0.413893,  0.866861, 0.288773}, {0.91838, 0.570739, 0.854218, 0.0983214,  0.646144, 0.344859, 0.791572, 0.603453, 0.953487, 0.0244117,  0.846679, 0.789597, 0.615306, 0.911468, 0.216052}, {0.0782882,  0.754169, 0.371387, 0.613461,  0.275309}, {{3, 1, 1}, {0, 1, 0}, {1, 1, 3}, {1, 0, 1}, {1, 1,  3}, {0, 1, 4}, {1, 2, 2}, {0, 2, 4}}, 0.571649, 0.957495, 0.7466,  0.986537}, -147.655}, {{{0, 0.653268, 0.386756, 0.892382,  0.888215, 0.00712471, 0, 0.0418966, 0.100809, 0.284762, 0.0536374,  0.0174849, 0, 0.254131, 0.495165, 0.438331, 0.106017, 0.0380788,  0, 0.416877, 0.684162, 0.73463, 0.424618, 0.141568, 0, 0,  0.112513, 0.777135, 0.678019, 0.155031, 0.459245, 0, 0.390379,  0.785637, 0.266816, 0.45212, 0.348482, 0, 0.684828, 0.982054,  0.398483, 0.330998, 0.430697, 0, 0.486889, 0.960152, 0.22498,  0.392618, 0.0700123, 0, 0, 0.27599, 0.490351, 0.968, 0.928445,  0.163477, 0, 0.713216, 0.289982, 0.773414, 0.704232, 0.322837, 0,  0.504345, 0.506598, 0.252112, 0.974354, 0.819517, 0, 0.524544,  0.85363, 0.643357, 0.38882, 0.0376548, 0, 0, 0.893478, 0.418376,  0.996201, 0.967642, 0.617488, 0, 0.928026, 0.0282008, 0.0391977,  0.454011, 0.21481, 0, 0.738219, 0.265784, 0.749778, 0.891973,  0.233874, 0, 0.759186, 0.497666, 0.917619, 0.414357, 0.234642,  0}, {0.644036, 0.274262, 0.0255378}, {0.196988, 0.750559,  0.855885, 0.0293367, 0.229345, 0.133071, 0.92786, 0.00113584,  0.190148, 0.67906, 0.71305, 0.262917, 0.924364, 0.929282,  0.821077}, {0.0290425, 0.165177, 0.431616, 0.903458,  0.614685}, {{1, 2, 0}, {2, 1, 0}, {3, 1, 0}, {0, 2, 2}, {2, 0,  3}, {3, 1, 0}, {1, 2, 2}, {3, 2, 1}}, 0.930535, 0.787579,  0.629196,  0.589147}, -150.984}, {{{0, 0.733547, 0.0370209, 0.773311,  0.559811, 0.504202, 0, 0.90395, 0.845451, 0.558675, 0.314054,  0.22489, 0, 0.132401, 0.295758, 0.389691, 0.295608, 0.311324, 0,  0.266716, 0.224513, 0.863992, 0.407866, 0.65203, 0, 0, 0.293978,  0.0764125, 0.77867, 0.0628832, 0.560431, 0, 0.0393916, 0.00535961,  0.503073, 0.0562294, 0.135442, 0, 0.159909, 0.944398, 0.742175,  0.910552, 0.0275079, 0, 0.64864, 0.352485, 0.614944, 0.716184,  0.381924, 0, 0, 0.127971, 0.750952, 0.308318, 0.729894, 0.833993,  0, 0.674539, 0.529647, 0.667011, 0.273562, 0.635148, 0, 0.524288,  0.163938, 0.217332, 0.499706, 0.364379, 0, 0.21954, 0.475157,  0.589154, 0.336871, 0.5709, 0, 0, 0.122673, 0.974211, 0.620687,  0.188976, 0.994701, 0, 0.223259, 0.31237, 0.459082, 0.160708,  0.54872, 0, 0.782722, 0.792071, 0.887146, 0.913572, 0.258435, 0,  0.628133, 0.669814, 0.413866, 0.894056, 0.408593, 0}, {0.194657,  0.824712, 0.557185}, {0.837693, 0.071984, 0.850501, 0.936498,  0.648717, 0.0772828, 0.627242, 0.624128, 0.189635, 0.916575,  0.0785226, 0.841406, 0.397564, 0.0294283, 0.16495}, {0.582971,  0.769431, 0.359614, 0.751084,  0.688915}, {{0, 1, 3}, {3, 1, 1}, {1, 0, 0}, {1, 0, 2}, {2, 0,  0}, {3, 1, 4}, {1, 0, 3}, {0, 0, 2}}, 0.360838, 0.164958,  0.926372,  0.13173}, -148.548}}; 

  for (unsigned int i = 0; i < sizeof (data) / sizeof (data[0]); ++i)
    {
      NormalDistribution prior_alpha = 
        normal_distribution (data[i].inputs.alphamean, 
                             data[i].inputs.alphastddev);
      NormalDistribution prior_logbeta = 
        normal_distribution (data[i].inputs.logbetamean, 
                             data[i].inputs.logbetastddev);

      for (unsigned int j = 0; j < 4; ++j)
        {
          for (unsigned int k = 0; k < 5; ++k)
            {
              data[i].inputs.alpha[j * 5 * 5 + k * 5 + k] = drand48 ();
            }
        }

      double output = qfunc (data[i].inputs.alpha,
                             4,
                             5,
                             data[i].inputs.logbeta,
                             3,
                             data[i].inputs.pz,
                             data[i].inputs.priorz,
                             data[i].inputs.ratings,
                             8,
                             &prior_alpha.base,
                             &prior_logbeta.base,
                             0);

      assert (fabs (output - data[i].desired_output) <=
              1e-5 * (1 + fabs (output) + fabs (data[i].desired_output)) ||
              ( fprintf (stderr, "%g ?= %g\n", output, data[i].desired_output),
                0 ));
    }
}

static void
test_qfunc_symmetric (void)
{
  QFuncTestDatum data[] = 
{{{{0, 0.812529, 0.916012, 0.889567, 0.395357, 0.574343, 0, 0.641843, 
    0.981265, 0.902453, 0.44459, 0.121949, 0, 0.432093, 0.539717, 
    0.00379296, 0.873433, 0.19517, 0, 0.335485, 0.729189, 0.551787, 
    0.323975, 0.7325, 0, 0, 0.549652, 0.248455, 0.379795, 0.570238, 
    0.737124, 0, 0.332443, 0.490228, 0.174882, 0.162781, 0.6906, 0, 
    0.508963, 0.272428, 0.718191, 0.568651, 0.0768703, 0, 0.732711, 
    0.714398, 0.695218, 0.881701, 0.397226, 0, 0, 0.985209, 0.143431, 
    0.557726, 0.664726, 0.435557, 0, 0.894976, 0.177931, 0.0944878, 
    0.698433, 0.562533, 0, 0.687703, 0.919606, 0.535652, 0.871933, 
    0.17874, 0, 0.647178, 0.817462, 0.303282, 0.101869, 0.914467, 0, 
    0, 0.103064, 0.608065, 0.220169, 0.517241, 0.117855, 0, 0.464634, 
    0.662443, 0.852515, 0.682298, 0.569658, 0, 0.484512, 0.758027, 
    0.983865, 0.00712475, 0.79681, 0, 0.83842, 0.448212, 0.135191, 
    0.61807, 0.191242, 0}, {0.63075, 0.831909, 0.516201}, {0.276776, 
    0.527687, 0.223844, 0.296032, 0.759535, 0.409832, 0.75921, 
    0.633589, 0.90702, 0.727534, 0.189552, 0.149077, 0.148994, 
    0.743669, 0.182427}, {0.352268, 0.310573, 0.295457, 0.047236, 
    0.734198}, {{1, 0, 3}, {1, 2, 1}, {1, 1, 3}, {3, 0, 3}, {3, 0, 
     3}, {1, 1, 0}, {2, 0, 3}, {3, 1, 0}}, 0.119331, 0.664706, 
   0.215327, 0.217997}, -126.528}};

  for (unsigned int i = 0; i < sizeof (data) / sizeof (data[0]); ++i)
    {
      NormalDistribution prior_alpha = 
        normal_distribution (data[i].inputs.alphamean, 
                             data[i].inputs.alphastddev);
      NormalDistribution prior_logbeta = 
        normal_distribution (data[i].inputs.logbetamean, 
                             data[i].inputs.logbetastddev);

      for (unsigned int j = 0; j < 4; ++j)
        {
          for (unsigned int k = 0; k < 5; ++k)
            {
              data[i].inputs.alpha[j * 5 * 5 + k * 5 + k] = drand48 ();
            }
        }

      double output = qfunc (data[i].inputs.alpha,
                             4,
                             5,
                             data[i].inputs.logbeta,
                             3,
                             data[i].inputs.pz,
                             data[i].inputs.priorz,
                             data[i].inputs.ratings,
                             8,
                             &prior_alpha.base,
                             &prior_logbeta.base,
                             1);

      assert (fabs (output - data[i].desired_output) <=
              1e-5 * (1 + fabs (output) + fabs (data[i].desired_output)) ||
              ( fprintf (stderr, "%g ?= %g\n", output, data[i].desired_output),
                0 ));
    }
}

typedef struct _DqfuncDalphaTestDatum DqfuncDalphaTestDatum;
struct _DqfuncDalphaTestDatum 
{ 
  struct
    {
      double    alpha[4 * 5 * 5];
      double    logbeta[3];
      double    pz[3 * 5];
      double    priorz[5];
      Rating    ratings[8];
      double    alphamean;
      double    alphastddev;
      double    logbetamean;
      double    logbetastddev;
    }                   inputs;
  double                dalpha[4*5*5];
};

static void
test_dqfuncdalpha (void)
{
  DqfuncDalphaTestDatum data[] = 
    {{{{0, 0.764304, 0.890998, 0.173232, 0.792734, 0.0174083, 0, 0.270284,  0.780239, 0.537789, 0.947814, 0.799876, 0, 0.563764, 0.503603,  0.914862, 0.348417, 0.455936, 0, 0.559337, 0.501745, 0.486836,  0.762782, 0.790878, 0, 0, 0.101807, 0.186352, 0.968494, 0.943297,  0.337503, 0, 0.295355, 0.795262, 0.150563, 0.320095, 0.025071, 0,  0.0150231, 0.612773, 0.37228, 0.225195, 0.451259, 0, 0.10917,  0.457418, 0.876777, 0.995323, 0.549833, 0, 0, 0.955673, 0.389942,  0.232541, 0.758955, 0.853867, 0, 0.203589, 0.264048, 0.815659,  0.516364, 0.908235, 0, 0.468786, 0.665096, 0.196269, 0.883164,  0.453762, 0, 0.0523225, 0.823988, 0.657969, 0.0025036, 0.943152,  0, 0, 0.36657, 0.781192, 0.00718081, 0.393319, 0.410897, 0,  0.39125, 0.77464, 0.634364, 0.55703, 0.187661, 0, 0.510592,  0.818705, 0.0406665, 0.279426, 0.0418065, 0, 0.15361, 0.844398,  0.396263, 0.588044, 0.101287, 0}, {0.020409, 0.738293,  0.585541}, {0.158135, 0.653839, 0.957101, 0.57836, 0.764816,  0.242942, 0.565851, 0.80372, 0.130452, 0.685912, 0.37819,  0.293128, 0.311746, 0.645245, 0.0987633}, {0.251322, 0.158137,  0.800848, 0.702501,  0.663277}, {{2, 0, 1}, {1, 1, 1}, {0, 1, 0}, {1, 2, 1}, {2, 1,  2}, {3, 1, 4}, {3, 0, 4}, {3, 2, 1}}, 0.0568496, 0.780439,  0.964207,  0.0777369}, {-0.188402, -1.11572, -1.33439, -0.0333839, -1.16504, -0.74519, 0.48123, -0.130072, -1.11186, -0.663711, -3.02764, -1.0607,  0.942135, -0.571333, -0.437559, -1.66433, -0.422074, -0.610007,  0.210719, -0.788568, -1.92697, -0.459759, -1.0208, -1.07482,  0.775157, 0.511357, -0.917744,  0.0794116, -1.43141, -1.38683, -0.171271, -1.04812, -0.076622, -1.09613, 0.266933, -0.11764, -1.61901, 0.693338,  0.650739, -0.738165, -0.307247, -1.43164, -0.465539, 0.513106,  0.256948, -0.344313, -2.82645, -1.43711, -0.550316, 0.897533,  0.354361, -1.58993, -0.928533, -0.119476, -1.08683, -1.1502,  0.0799208, -0.966811,  0.0727847, -1.07783, -0.298978, -2.13145, -0.478542, -0.183363, -0.641521, -0.0435013, -1.87004, -0.792868, 0.336535,  0.233439, -1.05834, -1.50618, -0.554836, -1.28761, 0.887973,  0.510011, -0.973559, -1.08647, 0.49277, -1.01802, -0.134194,  0.484621, -0.0866558, -0.934785, -2.49259, -0.374668, 0.0608958,  1.25525, -0.262662, -3.61723, 0.467794, -1.22303, 0.46511,  0.564606, -0.654165, -1.09586, -0.326123, -0.574982,  0.605693, -1.31072}}, {{{0, 0.898715, 0.1266, 0.00710612, 0.499377,  0.133899, 0, 0.883658, 0.441255, 0.695657, 0.00344779, 0.197746,  0, 0.0630657, 0.402529, 0.691702, 0.552501, 0.964302, 0, 0.151208,  0.533565, 0.751653, 0.261802, 0.48793, 0, 0, 0.476715, 0.971215,  0.297594, 0.410193, 0.578, 0, 0.844615, 0.290488, 0.910816,  0.444101, 0.960956, 0, 0.849233, 0.215159, 0.440653, 0.76321,  0.786167, 0, 0.81263, 0.748952, 0.210709, 0.821865, 0.661423, 0,  0, 0.215387, 0.459056, 0.560063, 0.173492, 0.738671, 0, 0.487841,  0.262469, 0.763299, 0.160671, 0.643226, 0, 0.971981, 0.852483,  0.71657, 0.68227, 0.122748, 0, 0.637324, 0.275916, 0.91906,  0.336581, 0.824694, 0, 0, 0.526965, 0.708351, 0.514716, 0.163271,  0.311578, 0, 0.249296, 0.954653, 0.989779, 0.572907, 0.761455, 0,  0.692184, 0.22648, 0.412236, 0.118228, 0.720203, 0, 0.373997,  0.695666, 0.435958, 0.597455, 0.736673, 0}, {0.419749, 0.516898,  0.260874}, {0.911979, 0.892785, 0.808547, 0.746158, 0.748708,  0.581207, 0.559252, 0.791506, 0.758929, 0.00830017, 0.797797,  0.0993216, 0.532449, 0.596065, 0.679569}, {0.379118, 0.158453,  0.900399, 0.243611,  0.781663}, {{1, 0, 3}, {2, 2, 1}, {3, 0, 2}, {1, 2, 0}, {0, 0,  0}, {2, 0, 4}, {2, 1, 4}, {3, 0, 4}}, 0.42178, 0.480649,  0.726712, 0.520789}, {0.830426, -1.96448, 1.60133,  2.1831, -0.152353, 0.265285, 2.28865, -1.87859, 0.152266, -1.02486,  0.872907, 1.18731, 2.11964, 1.81976,  0.242646, -2.16245, -0.391247, -2.25504, 2.23038,  1.49269, -1.44926, -1.30314, 0.955321, -0.100008, 2.21718, 1.60656,  0.175749, -2.17345, -0.316308, 0.504793, -0.565247,  2.39738, -1.66949, -0.420703, -1.97124, -0.426792, -2.16207,  2.51064, -2.87888, 1.39644, -0.450064, -1.22221, -1.32981,  1.45263, -1.45353, -2.0484, 1.45096, -1.50644, -1.89356, 2.55148,  2.81636, 0.574878, 0.336741, -0.170145, -0.523947, -1.09423,  2.58106, 0.125079, 1.27499, -3.50753, 2.08784, -1.19327,  3.05256, -2.10532, -4.09032, -0.908001, -1.51356, 2.20538,  2.92548, -2.92577, 1.10928, -2.84316, 0.807089, -1.52513, 1.38124,  2.7429, -0.0439228, -2.31593, 0.0168367, 0.446763, 1.08918,  2.80918, 0.0611804, -2.07647, -3.59894, -0.285249, -1.1934,  1.47751, -0.862776, 0.240052, 0.412191, 1.89406, -2.19496,  2.52015, -0.53541, -0.880414, 0.391617, -1.54534, -1.07637,  1.56585}}, {{{0, 0.509801, 0.587865, 0.918165, 0.77463, 0.761093,  0, 0.00665809, 0.358913, 0.983125, 0.00216453, 0.998358, 0,  0.561116, 0.883803, 0.469715, 0.402293, 0.881547, 0, 0.504685,  0.311263, 0.501895, 0.637937, 0.723021, 0, 0, 0.889483, 0.0212451,  0.911224, 0.202233, 0.379682, 0, 0.43338, 0.993059, 0.427602,  0.618589, 0.426722, 0, 0.634146, 0.444477, 0.616424, 0.428364,  0.0730301, 0, 0.560674, 0.146709, 0.026071, 0.191483, 0.0559895,  0, 0, 0.835446, 0.524176, 0.553546, 0.332968, 0.945963, 0,  0.502931, 0.642322, 0.130735, 0.566281, 0.0695509, 0, 0.649263,  0.703133, 0.947693, 0.642829, 0.0151163, 0, 0.258656, 0.331269,  0.214464, 0.942086, 0.697982, 0, 0, 0.18456, 0.188393, 0.750603,  0.641992, 0.349114, 0, 0.664217, 0.197057, 0.309024, 0.403151,  0.161286, 0, 0.554735, 0.178289, 0.83687, 0.0917348, 0.905472, 0,  0.475155, 0.889177, 0.448906, 0.890356, 0.2165, 0}, {0.557909,  0.234442, 0.94827}, {0.518518, 0.373348, 0.0460483, 0.197667,  0.876526, 0.0242343, 0.381831, 0.000609685, 0.567502, 0.621083,  0.220546, 0.445875, 0.389213, 0.784213, 0.128811}, {0.540402,  0.914058, 0.895036, 0.679905,  0.650046}, {{2, 2, 3}, {1, 0, 2}, {2, 0, 2}, {2, 2, 4}, {1, 2,  2}, {0, 0, 2}, {1, 0, 4}, {1, 2, 1}}, 0.697558, 0.337128,  0.445463, 0.701777}, {6.5441, 1.81886,  0.204874, -1.85926, -0.573063, -0.500847, 6.35736, 5.64399,  3.09703, -2.47311, 6.1475, -2.64151, 6.08621, 1.21143, -1.63246,  2.06398, 2.66461, -1.93529, 6.2722, 1.75278, 3.73978,  1.96592, -0.81405, -0.0579753, 6.72478, 7.14173, -2.09173,  5.43603, -1.72066, 4.11224, 3.46122, 6.57234, 1.10979, -2.4286,  2.31924, 0.914609, 1.73389, 6.09577, 0.769342, 2.48637, 1.10792,  0.966484, 4.61397, 7.92077, 1.31008, 5.50251, 6.39985, 3.19165,  6.42358, 5.47233, 7.04864, -1.06669, 0.905079, 0.965646,  3.0721, -2.05136, 7.39322, 1.43706, -0.393382, 4.75203, 1.35816,  6.24493, 6.91623, -0.415173, -0.910153, -2.05228, 0.797425, 7.1818,  5.69507, 2.66243, 3.66205, 4.80495, -3.54894, -0.122199, 6.65977,  6.13751, 4.51365, 4.47992, -0.466718, 0.488903, 3.06581, 6.13751,  0.293355, 4.40369, 3.41854, 2.59036, 4.71842, 6.13751, 1.25664,  4.56882, -1.22574, 5.33037, -1.82934, 6.13751, 1.95683, -1.68597,  2.18778, -1.69634, 4.23262, 6.13751}}};  

  for (unsigned int i = 0; i < sizeof (data) / sizeof (data[0]); ++i)
    {
      double dalpha[4*5*5];
      double dlogbeta[3];
      NormalDistribution prior_alpha = 
        normal_distribution (data[i].inputs.alphamean, 
                             data[i].inputs.alphastddev);
      NormalDistribution prior_logbeta = 
        normal_distribution (data[i].inputs.logbetamean, 
                             data[i].inputs.logbetastddev);

      memset (dalpha, lrand48 (), 4*5*5 * sizeof (dalpha[0]));

      for (unsigned int j = 0; j < 4; ++j)
        {
          for (unsigned int k = 0; k < 5; ++k)
            {
              data[i].inputs.alpha[j * 5 * 5 + k * 5 + k] = drand48 ();
            }
        }

      dqfunc (dalpha,
              dlogbeta,
              data[i].inputs.alpha,
              4,
              5,
              data[i].inputs.logbeta,
              3,
              data[i].inputs.pz,
              data[i].inputs.ratings,
              8,
              &prior_alpha.base,
              &prior_logbeta.base,
              0);

      for (unsigned int j = 0; j < 4*5*5; ++j)
        {
          if (j % 5 == (j / 5) % 5)
            {
              assert (dalpha[j] == 0.0 || 
                      (fprintf (stderr, "%u %u: %g ?= 0\n", i, j, dalpha[j]), 
                       0));
            }
          else
            {
              assert (fabs (dalpha[j] - data[i].dalpha[j]) <=
                      5e-5 * (1 + fabs (dalpha[j]) + fabs (data[i].dalpha[j])) ||
                      ( fprintf (stderr, "%u %u: %g ?= %g\n", i, j, dalpha[j], data[i].dalpha[j]),
                        0 ));
            }
        }
    }
}

static void
test_dqfuncdalpha_symmetric (void)
{
  DqfuncDalphaTestDatum data[] = 
    {{{{0, 0.582622, 0.325795, 0.834215, 0.712378, 0.503009, 0, 0.986335,  0.824761, 0.53431, 0.342838, 0.0111734, 0, 0.471548, 0.513152,  0.129525, 0.884654, 0.991869, 0, 0.901753, 0.109343, 0.959594,  0.161725, 0.989174, 0, 0, 0.151016, 0.573031, 0.0261749, 0.290562,  0.568394, 0, 0.247236, 0.19196, 0.578183, 0.0653851, 0.260901, 0,  0.367199, 0.0438732, 0.722548, 0.249728, 0.895651, 0, 0.530721,  0.593023, 0.365074, 0.903782, 0.628968, 0, 0, 0.483679, 0.405481,  0.742057, 0.639794, 0.332664, 0, 0.832449, 0.715882, 0.349232,  0.76427, 0.585213, 0, 0.523921, 0.771049, 0.698885, 0.324312,  0.156723, 0, 0.727176, 0.976338, 0.0745841, 0.261072, 0.196455, 0,  0, 0.383315, 0.70951, 0.35729, 0.567487, 0.899636, 0, 0.304029,  0.615233, 0.927693, 0.566972, 0.47158, 0, 0.899352, 0.578461,  0.802701, 0.886366, 0.37543, 0, 0.807412, 0.103816, 0.562054,  0.218708, 0.0802364, 0}, {0.127479, 0.48747, 0.957636}, {0.883782,  0.744164, 0.77796, 0.600346, 0.316295, 0.844528, 0.473931,  0.985112, 0.388602, 0.277556, 0.00235157, 0.0857606, 0.810141,  0.474855, 0.115985}, {0.71033, 0.00272871, 0.371039, 0.553931,  0.491623}, {{0, 1, 0}, {2, 2, 0}, {3, 0, 0}, {1, 0, 1}, {0, 1,  0}, {2, 2, 1}, {1, 0, 3}, {0, 0, 0}}, 0.922492, 0.24356,  0.0664605, 0.533987}, {13.2071, 10.0791, 17.785, 1.67868, 6.47974,  10.0791, 16.5354, -1.58583, 3.83927, 13.7637, 17.785, -1.58583,  17.0244, 16.3331, 14.7072, 1.67868, 3.83927, 16.3331, 16.3731,  1.05208, 6.47974, 13.7637, 14.7072, 1.05208, 16.0515, 16.0461,  25.7867, 12.2775, 30.0285, 21.7997, 25.7867, 15.1367, 22.5513,  23.7246, 11.5723, 12.2775, 22.5513, 16.0055, 18.3632, 30.2379,  30.0285, 23.7246, 18.3632, 15.2114, 13.1419, 21.7997, 11.5723,  30.2379, 13.1419, 15.7431, 15.5509, 14.6314, 16.1149, 5.05687,  9.29088, 14.6314, 15.5559, 1.21167, 5.98866, 19.2468, 16.1149,  1.21167, 17.831, 14.3905, 5.4549, 5.05687, 5.98866, 14.3905,  17.0019, 6.85167, 9.29088, 19.2468, 5.4549, 6.85167, 15.873,  14.8524, 17.7014, 6.56354, 18.7328, 11.8375, 17.7014, 15.8149,  21.2445, 10.6064, -0.0383996, 6.56354, 21.2445, 15.8421, 0.969053,  11.8166, 18.7328, 10.6064, 0.969053, 15.784, 4.02457,  11.8375, -0.0383996, 11.8166, 4.02457,  15.6795}}, {{{0, 0.0387107, 0.499396, 0.2885, 0.933642, 0.722416,  0, 0.654868, 0.814569, 0.948529, 0.333814, 0.377312, 0, 0.812217,  0.862769, 0.523674, 0.902457, 0.696232, 0, 0.152438, 0.520945,  0.531418, 0.142301, 0.660816, 0, 0, 0.598453, 0.287858, 0.0758408,  0.126828, 0.559742, 0, 0.788462, 0.787341, 0.193187, 0.837326,  0.133594, 0, 0.972772, 0.244657, 0.503511, 0.756282, 0.160555, 0,  0.381889, 0.979838, 0.853826, 0.464323, 0.22945, 0, 0, 0.458893,  0.322407, 0.322022, 0.568635, 0.860441, 0, 0.0345488, 0.246181,  0.441807, 0.300699, 0.246086, 0, 0.45884, 0.24862, 0.463373,  0.112492, 0.486068, 0, 0.00396235, 0.959862, 0.35621, 0.325513,  0.622074, 0, 0, 0.980024, 0.502384, 0.86119, 0.392623, 0.521131,  0, 0.179977, 0.539169, 0.823988, 0.66069, 0.145428, 0, 0.292988,  0.382182, 0.359991, 0.899342, 0.834148, 0, 0.133562, 0.896618,  0.786849, 0.34808, 0.1296, 0}, {0.936757, 0.43064,  0.0225666}, {0.507526, 0.956733, 0.928256, 0.161376, 0.114903,  0.435602, 0.748279, 0.622207, 0.290915, 0.774912, 0.602851,  0.329219, 0.908733, 0.414921, 0.703509}, {0.495071, 0.775171,  0.518303, 0.91666,  0.146991}, {{3, 1, 2}, {0, 2, 0}, {1, 2, 2}, {2, 1, 3}, {1, 2,  0}, {0, 2, 3}, {1, 2, 0}, {1, 2, 1}}, 0.645571, 0.581546,  0.48602, 0.124425}, {1.62642, 3.77022, 0.512129, 1.50147, -2.11196,  3.77022, 2.11378, 0.371176, -1.14077, -1.53412, 0.512129,  0.371176, 2.53661, -1.53489, -0.828401,  1.50147, -1.14077, -1.53489, 1.72905,  2.81191, -2.11196, -1.53412, -0.828401, 2.81191, 2.38332,  1.27856, -0.460252, 0.918317, 3.53786, 2.76669, -0.460252,  1.98577, -1.42957, -0.85597, 2.8638, 0.918317, -1.42957,  2.09262, -1.76418, 3.05756, 3.53786, -0.85597, -1.76418, 2.40542,  2.36414, 2.76669, 2.8638, 3.05756, 2.36414, 2.60171, 2.12301,  1.36607, 2.19765, 1.44592, 0.682348, 1.36607, 2.22565, 4.15692,  1.5088, 1.53337, 2.19765, 4.15692, 2.16525, 0.332171, 2.74825,  1.44592, 1.5088, 0.332171, 1.5797, 3.04902, 0.682348, 1.53337,  2.74825, 3.04902, 2.23999, 2.17735, -1.82391, 0.430172, -1.166,  1.84639, -1.82391, 2.33557, 2.13852, 0.877328, -0.830038, 0.430172,  2.13852, 1.23223, 1.90671, 0.728464, -1.166, 0.877328, 1.90671,  2.05076, 3.44694, 1.84639, -0.830038, 0.728464, 3.44694,  2.28161}}, {{{0, 0.138045, 0.624813, 0.557764, 0.963049, 0.0231421,  0, 0.189211, 0.809486, 0.340841, 0.732228, 0.414299, 0, 0.206635,  0.0116219, 0.823495, 0.999378, 0.503126, 0, 0.516551, 0.0483241,  0.481076, 0.586466, 0.369559, 0, 0, 0.402753, 0.89953, 0.100447,  0.245134, 0.264708, 0, 0.274716, 0.542682, 0.282086, 0.241566,  0.0855052, 0, 0.733197, 0.941245, 0.509338, 0.671206, 0.526562, 0,  0.929623, 0.685843, 0.671828, 0.0234358, 0.413072, 0, 0,  0.637519, 0.190752, 0.436969, 0.0435129, 0.234766, 0, 0.291222,  0.336523, 0.798379, 0.970058, 0.0165055, 0, 0.793841, 0.516293,  0.728492, 0.931, 0.0606438, 0, 0.575048, 0.219154, 0.259794,  0.534082, 0.645426, 0, 0, 0.533311, 0.587967, 0.510646, 0.232353,  0.895791, 0, 0.397215, 0.0736768, 0.188841, 0.661025, 0.105993, 0,  0.737154, 0.390462, 0.690967, 0.0894875, 0.943313, 0, 0.874169,  0.962474, 0.158487, 0.88267, 0.299121, 0}, {0.74332, 0.898693,  0.348587}, {0.653696, 0.21001, 0.310726, 0.837941, 0.421342,  0.314218, 0.913512, 0.764265, 0.232502, 0.653193, 0.807519,  0.0271106, 0.84204, 0.962227, 0.718031}, {0.0837973, 0.96787,  0.999752, 0.559544,  0.201128}, {{1, 2, 4}, {1, 1, 2}, {2, 1, 3}, {0, 1, 0}, {2, 1,  0}, {0, 1, 1}, {2, 1, 1}, {2, 1, 4}}, 0.668749, 0.256432,  0.660851, 0.85254}, {10.0764, 14.7073, -0.15809, 3.10445, -10.3835,  14.7073, 9.46798, 14.3668, -4.57173, 9.53605, -0.15809, 14.3668,  11.2686, 15.0188, 22.1761, 3.10445, -4.57173, 15.0188, 10.6722,  5.09487, -10.3835, 9.53605, 22.1761, 5.09487, 11.3244, 10.7793,  8.70342, -7.42835, 18.3833, 12.7647, 8.70342, 11.0298, 11.002,  4.34247, 12.7452, -7.42835, 11.002, 9.75303, -1.99848, -10.7019,  18.3833, 4.34247, -1.99848, 10.8788, -8.98267, 12.7647,  12.7452, -10.7019, -8.98267, 10.2158, 10.4021, -1.03251, 15.1408,  6.4105, 19.7915, -1.03251, 11.8695, 12.9801, 9.47653, -6.88411,  15.1408, 12.9801, 13.1281, -5.111, 4.29599, 6.4105,  9.47653, -5.111, 10.6539, 1.54076, 19.7915, -6.88411, 4.29599,  1.54076, 11.0684, 10.17, 4.11934, 2.45698, 4.80869, 13.2729,  4.11934, 10.17, 8.25868, 18.0991, 14.5964, 2.45698, 8.25868,  10.17, -2.08052, 8.46407, 4.80869, 18.0991, -2.08052,  10.17, -6.24782, 13.2729, 14.5964, 8.46407, -6.24782, 10.17}}};

  for (unsigned int i = 0; i < sizeof (data) / sizeof (data[0]); ++i)
    {
      double dalpha[4*5*5];
      double dlogbeta[3];
      NormalDistribution prior_alpha = 
        normal_distribution (data[i].inputs.alphamean, 
                             data[i].inputs.alphastddev);
      NormalDistribution prior_logbeta = 
        normal_distribution (data[i].inputs.logbetamean, 
                             data[i].inputs.logbetastddev);

      memset (dalpha, lrand48 (), 4*5*5 * sizeof (dalpha[0]));

      for (unsigned int j = 0; j < 4; ++j)
        {
          for (unsigned int k = 0; k < 5; ++k)
            {
              data[i].inputs.alpha[j * 5 * 5 + k * 5 + k] = drand48 ();
            }
        }

      dqfunc (dalpha,
              dlogbeta,
              data[i].inputs.alpha,
              4,
              5,
              data[i].inputs.logbeta,
              3,
              data[i].inputs.pz,
              data[i].inputs.ratings,
              8,
              &prior_alpha.base,
              &prior_logbeta.base,
              1);

      for (unsigned int j = 0; j < 4*5*5; ++j)
        {
          if (j % 5 <= (j / 5) % 5)
            {
              assert (dalpha[j] == 0.0 || 
                      (fprintf (stderr, "%u %u: %g ?= 0\n", i, j, dalpha[j]), 
                       0));
            }
          else
            {
              assert (fabs (dalpha[j] - data[i].dalpha[j]) <=
                      5e-5 * (1 + fabs (dalpha[j]) + fabs (data[i].dalpha[j])) ||
                      ( fprintf (stderr, "%u %u: %g ?= %g\n", i, j, dalpha[j], data[i].dalpha[j]),
                        1 ));
            }
        }
    }
}

typedef struct _DqfuncDlogbetaTestDatum DqfuncDlogbetaTestDatum;
struct _DqfuncDlogbetaTestDatum 
{ 
  struct
    {
      double    alpha[4 * 5 * 5];
      double    logbeta[3];
      double    pz[3 * 5];
      double    priorz[5];
      Rating    ratings[8];
      double    alphamean;
      double    alphastddev;
      double    logbetamean;
      double    logbetastddev;
    }                   inputs;
  double                desired_output[3];
};

static void
test_dqfuncdlogbeta (void)
{
  DqfuncDlogbetaTestDatum data[] = 
    {{{{0, 0.932207, 0.00769661, 0.721531, 0.50061, 0.0882734, 0,  0.0138601, 0.759923, 0.208167, 0.970559, 0.409867, 0, 0.31571,  0.495391, 0.798841, 0.237613, 0.966669, 0, 0.719157, 0.916379,  0.563342, 0.364319, 0.862035, 0, 0, 0.423352, 0.278521, 0.536353,  0.0924323, 0.491146, 0, 0.270825, 0.814822, 0.591823, 0.402872,  0.256965, 0, 0.0548989, 0.383656, 0.432313, 0.847097, 0.739189, 0,  0.888264, 0.633472, 0.609485, 0.77252, 0.169108, 0, 0, 0.717094,  0.046143, 0.408201, 0.307073, 0.293742, 0, 0.767622, 0.871848,  0.214641, 0.802596, 0.496797, 0, 0.0570258, 0.622818, 0.399724,  0.239833, 0.00212695, 0, 0.239162, 0.967411, 0.392735, 0.262938,  0.350898, 0, 0, 0.333938, 0.78325, 0.490418, 0.18179, 0.616845, 0,  0.737107, 0.0822173, 0.874717, 0.323103, 0.969486, 0, 0.210369,  0.660076, 0.520507, 0.472689, 0.153343, 0, 0.0372582, 0.120783,  0.232856, 0.151216, 0.798096, 0}, {0.153373, 0.840121,  0.888278}, {0.447198, 0.819434, 0.0568707, 0.39786, 0.265408,  0.20259, 0.319763, 0.315643, 0.390691, 0.879486, 0.350277,  0.105273, 0.730615, 0.358979, 0.877589}, {0.95193, 0.693356,  0.238196, 0.644733,  0.800714}, {{0, 2, 2}, {2, 2, 4}, {3, 0, 2}, {3, 2, 1}, {2, 0,  4}, {3, 1, 1}, {2, 2, 2}, {2, 2, 2}}, 0.895261, 0.0848231,  0.804612,  0.912435}, {0.234308, -0.985902, -2.2844}}, {{{0, 0.448063,  0.265389, 0.747741, 0.514576, 0.182655, 0, 0.0627989, 0.427978,  0.198933, 0.791964, 0.183312, 0, 0.0777002, 0.0936595, 0.0613489,  0.824333, 0.200111, 0, 0.141729, 0.367992, 0.586137, 0.555379,  0.341016, 0, 0, 0.472732, 0.501314, 0.750767, 0.42858, 0.0246694,  0, 0.235926, 0.00302641, 0.914005, 0.842015, 0.173127, 0,  0.575049, 0.715072, 0.0500512, 0.989814, 0.497349, 0, 0.621412,  0.988702, 0.165481, 0.297237, 0.479683, 0, 0, 0.62071, 0.579344,  0.741858, 0.138667, 0.147978, 0, 0.0780296, 0.991091, 0.710087,  0.123308, 0.842104, 0, 0.988065, 0.796082, 0.281294, 0.668977,  0.413016, 0, 0.0810104, 0.231243, 0.679163, 0.915667, 0.459598, 0,  0, 0.24254, 0.513682, 0.61843, 0.979915, 0.621831, 0, 0.934338,  0.876572, 0.841248, 0.473853, 0.856308, 0, 0.885481, 0.131161,  0.350544, 0.0142043, 0.897416, 0, 0.335079, 0.0692505, 0.345227,  0.4844, 0.254068, 0}, {0.838008, 0.666064, 0.568732}, {0.79447,  0.595468, 0.152382, 0.950302, 0.814555, 0.973637, 0.218044,  0.0737304, 0.973307, 0.499784, 0.361736, 0.18825, 0.842147,  0.14924, 0.347532}, {0.290834, 0.507068, 0.0799898, 0.00230472,  0.806434}, {{3, 2, 4}, {0, 1, 1}, {2, 1, 2}, {3, 1, 1}, {0, 0,  3}, {1, 2, 2}, {0, 1, 3}, {0, 1, 0}}, 0.253, 0.241982, 0.336241,  0.237702}, {-10.092, -9.49715, -4.31556}}, {{{0, 0.458529,  0.646514, 0.183858, 0.2874, 0.643974, 0, 0.672877, 0.965814,  0.21367, 0.670667, 0.173092, 0, 0.604078, 0.0254197, 0.82852,  0.0238522, 0.256546, 0, 0.734586, 0.321452, 0.943862, 0.254241,  0.928151, 0, 0, 0.0684524, 0.701881, 0.918001, 0.690449, 0.609923,  0, 0.0553665, 0.734142, 0.403049, 0.965949, 0.382489, 0,  0.768329, 0.18938, 0.295282, 0.209397, 0.164251, 0, 0.16396,  0.466762, 0.185545, 0.907705, 0.429374, 0, 0, 0.14531, 0.241682,  0.653464, 0.501223, 0.0768574, 0, 0.539802, 0.735463, 0.810774,  0.466934, 0.484435, 0, 0.00132091, 0.407725, 0.500986, 0.101946,  0.232992, 0, 0.218345, 0.205704, 0.892549, 0.0687415, 0.054385, 0,  0, 0.738942, 0.707004, 0.161037, 0.625011, 0.593632, 0, 0.465322,  0.507573, 0.123788, 0.516774, 0.92552, 0, 0.772109, 0.313014,  0.0498398, 0.441085, 0.770788, 0, 0.905289, 0.548854, 0.339139,  0.537796, 0.686944, 0}, {0.343151, 0.44659, 0.469055}, {0.632559,  0.604209, 0.739586, 0.308018, 0.00754846, 0.0105774, 0.274264,  0.800445, 0.883761, 0.493803, 0.348744, 0.0283361, 0.570747,  0.443963, 0.90766}, {0.257548, 0.665458, 0.895109, 0.568521,  0.719751}, {{1, 2, 0}, {1, 2, 4}, {2, 1, 0}, {3, 2, 1}, {3, 2,  2}, {0, 0, 4}, {3, 1, 0}, {0, 1, 3}}, 0.978513, 0.551958,  0.121931,  0.250697}, {-3.50387, -7.23923, -7.78103}}, {{{0, 0.345954,  0.947749, 0.382345, 0.942679, 0.338406, 0, 0.937172, 0.108082,  0.142233, 0.454645, 0.443369, 0, 0.759337, 0.113897, 0.883898,  0.999406, 0.851678, 0, 0.85635, 0.21844, 0.104297, 0.283157,  0.136598, 0, 0, 0.239927, 0.552338, 0.161226, 0.885901, 0.893973,  0, 0.604589, 0.77888, 0.943223, 0.555567, 0.667417, 0, 0.670799,  0.800989, 0.100922, 0.224048, 0.911461, 0, 0.687092, 0.217024,  0.224642, 0.0597836, 0.830743, 0, 0, 0.998583, 0.120346, 0.776627,  0.694145, 0.758656, 0, 0.568008, 0.615401, 0.808243, 0.864684,  0.963419, 0, 0.83652, 0.865021, 0.309117, 0.296002, 0.165722, 0,  0.0640311, 0.208195, 0.071954, 0.25426, 0.376939, 0, 0, 0.991171,  0.847312, 0.194477, 0.546196, 0.992588, 0, 0.726966, 0.41785,  0.852051, 0.233932, 0.158958, 0, 0.802449, 0.0438081, 0.369248,  0.195539, 0.965929, 0, 0.178787, 0.0601312, 0.899537, 0.800207,  0.114756, 0}, {0.851936, 0.827583, 0.545947}, {0.737818, 0.860765,  0.980272, 0.35147, 0.191622, 0.868177, 0.253306, 0.93362,  0.33957, 0.634245, 0.0943478, 0.131171, 0.295762, 0.264997,  0.898809}, {0.165242, 0.116975, 0.204866, 0.999271,  0.365035}, {{0, 2, 3}, {1, 0, 1}, {3, 2, 4}, {3, 0, 3}, {3, 0,  1}, {2, 0, 2}, {1, 2, 0}, {3, 1, 2}}, 0.00221842, 0.35293,  0.171688,  0.819088}, {-4.05889, -3.77099, -0.683228}}, {{{0, 0.264401,  0.492165, 0.191416, 0.467618, 0.0727791, 0, 0.623988, 0.93811,  0.533998, 0.733209, 0.989743, 0, 0.843763, 0.402826, 0.437447,  0.724745, 0.944954, 0, 0.237584, 0.320472, 0.519879, 0.945683,  0.872549, 0, 0, 0.318253, 0.166949, 0.773995, 0.0534608,  0.0538525, 0, 0.674784, 0.582578, 0.585843, 0.981073, 0.0507964,  0, 0.644468, 0.0518453, 0.247865, 0.0610536, 0.800705, 0,  0.649019, 0.810418, 0.336308, 0.855751, 0.411435, 0, 0, 0.489946,  0.816429, 0.910068, 0.538886, 0.171693, 0, 0.64948, 0.136073,  0.485425, 0.11784, 0.974695, 0, 0.553495, 0.899582, 0.136767,  0.923899, 0.909027, 0, 0.847737, 0.888902, 0.862845, 0.108322,  0.198718, 0, 0, 0.0784844, 0.526537, 0.252571, 0.787283, 0.588538,  0, 0.710108, 0.342503, 0.248397, 0.416845, 0.0606284, 0,  0.206429, 0.762972, 0.299005, 0.0859331, 0.652934, 0, 0.86339,  0.162238, 0.162034, 0.743907, 0.0156536, 0}, {0.273335, 0.299189,  0.635585}, {0.816936, 0.194851, 0.772652, 0.383014, 0.0296525,  0.606313, 0.0625439, 0.0405113, 0.781255, 0.189468, 0.00191559,  0.834082, 0.0182828, 0.890463, 0.915982}, {0.181148, 0.154892,  0.728225, 0.753948,  0.437241}, {{2, 2, 3}, {2, 2, 0}, {2, 0, 3}, {1, 1, 0}, {1, 2,  0}, {1, 1, 2}, {0, 2, 3}, {1, 0, 0}}, 0.139239, 0.45489,  0.454759,  0.801656}, {-0.903418, -0.526928, -3.15154}}, {{{0, 0.322303,  0.260039, 0.682107, 0.418642, 0.292651, 0, 0.653727, 0.619563,  0.378131, 0.511396, 0.464259, 0, 0.617648, 0.544049, 0.493113,  0.573796, 0.701665, 0, 0.362901, 0.33822, 0.84557, 0.947717,  0.92566, 0, 0, 0.198981, 0.39068, 0.492958, 0.124004, 0.876678, 0,  0.130641, 0.81085, 0.705361, 0.584028, 0.476914, 0, 0.191287,  0.32723, 0.072632, 0.0126554, 0.573639, 0, 0.783181, 0.579519,  0.43886, 0.871974, 0.42028, 0, 0, 0.241299, 0.593289, 0.924257,  0.49462, 0.0423175, 0, 0.202609, 0.431299, 0.370617, 0.165639,  0.0719685, 0, 0.620448, 0.665255, 0.581612, 0.595054, 0.429162, 0,  0.338025, 0.50898, 0.582399, 0.855523, 0.554844, 0, 0, 0.929461,  0.143539, 0.983549, 0.134564, 0.688162, 0, 0.55025, 0.0592925,  0.639944, 0.645844, 0.347641, 0, 0.627994, 0.269328, 0.480205,  0.275672, 0.00754521, 0, 0.604072, 0.898593, 0.680618, 0.578384,  0.266047, 0}, {0.389613, 0.0982189, 0.722861}, {0.711203,  0.460153, 0.95468, 0.739312, 0.576639, 0.771991, 0.40443, 0.68002,  0.936694, 0.126147, 0.0567893, 0.0520259, 0.667367, 0.645942,  0.781117}, {0.0444807, 0.0632947, 0.747349, 0.100499,  0.466097}, {{2, 0, 0}, {2, 0, 2}, {3, 0, 3}, {2, 1, 3}, {0, 1,  0}, {0, 1, 4}, {3, 0, 0}, {2, 0, 4}}, 0.797248, 0.357736,  0.00228049,  0.743236}, {-4.16394, -0.953437, -1.30445}}, {{{0, 0.086045,  0.897584, 0.0476008, 0.00392401, 0.509406, 0, 0.125593, 0.643171,  0.323904, 0.572712, 0.999446, 0, 0.586382, 0.271879, 0.905345,  0.353503, 0.805264, 0, 0.227398, 0.84205, 0.606154, 0.704765,  0.761301, 0, 0, 0.0448027, 0.248417, 0.702485, 0.0180648,  0.958758, 0, 0.350834, 0.654884, 0.0141408, 0.449351, 0.225241, 0,  0.0117129, 0.690236, 0.876639, 0.225795, 0.425331, 0, 0.418358,  0.971294, 0.872292, 0.620067, 0.19096, 0, 0, 0.129244, 0.266138,  0.915302, 0.429659, 0.0844408, 0, 0.0177211, 0.212817, 0.411594,  0.125683, 0.666887, 0, 0.557933, 0.397454, 0.676332, 0.441646,  0.54622, 0, 0.707217, 0.799693, 0.215851, 0.120889, 0.288859, 0,  0, 0.828399, 0.343559, 0.500822, 0.0978995, 0.699155, 0,  0.0774202, 0.585521, 0.66824, 0.614715, 0.0596992, 0, 0.372704,  0.256646, 0.489031, 0.392812, 0.81477, 0, 0.859193, 0.812699,  0.951165, 0.26855, 0.151976, 0}, {0.0130065, 0.735314,  0.147661}, {0.863116, 0.184608, 0.391756, 0.646838, 0.765217,  0.485452, 0.314336, 0.0613177, 0.0969761, 0.870738, 0.254636,  0.688614, 0.84033, 0.381706, 0.861825}, {0.873843, 0.981137,  0.569007, 0.910659,  0.605293}, {{1, 0, 1}, {2, 0, 2}, {2, 1, 3}, {1, 0, 4}, {0, 1,  2}, {0, 0, 2}, {2, 1, 2}, {0, 1, 0}}, 0.829162, 0.556001,  0.175345, 0.457632}, {-0.107731, -6.37106,  0.132188}}}; 

  for (unsigned int i = 0; i < sizeof (data) / sizeof (data[0]); ++i)
    {
      double dalpha[4*5*5];
      double dlogbeta[3];
      NormalDistribution prior_alpha = 
        normal_distribution (data[i].inputs.alphamean, 
                             data[i].inputs.alphastddev);
      NormalDistribution prior_logbeta = 
        normal_distribution (data[i].inputs.logbetamean, 
                             data[i].inputs.logbetastddev);

      memset (dlogbeta, lrand48 (), 3 * sizeof (dlogbeta[0]));

      for (unsigned int j = 0; j < 4; ++j)
        {
          for (unsigned int k = 0; k < 5; ++k)
            {
              data[i].inputs.alpha[j * 5 * 5 + k * 5 + k] = drand48 ();
            }
        }

      dqfunc (dalpha,
              dlogbeta,
              data[i].inputs.alpha,
              4,
              5,
              data[i].inputs.logbeta,
              3,
              data[i].inputs.pz,
              data[i].inputs.ratings,
              8,
              &prior_alpha.base,
              &prior_logbeta.base,
              0);

      for (unsigned int j = 0; j < 3; ++j)
        {
          assert (fabs (dlogbeta[j] - data[i].desired_output[j]) <=
                  1e-5 * (1 + fabs (dlogbeta[j]) + fabs (data[i].desired_output[j])) ||
                  ( fprintf (stderr, "%u %u: %g ?= %g\n", i, j, dlogbeta[j], data[i].desired_output[j]),
                    0 ));
        }
    }
}

static void
test_dqfuncdlogbeta_symmetric (void)
{
  DqfuncDlogbetaTestDatum data[] = 
    {{{{0, 0.218116, 0.305695, 0.180994, 0.0547372, 0.021731, 0, 0.59356,  0.32899, 0.675257, 0.791828, 0.592057, 0, 0.922544, 0.400438,  0.0942889, 0.209129, 0.867287, 0, 0.249237, 0.566157, 0.626506,  0.150823, 0.144542, 0, 0, 0.665299, 0.938491, 0.76372, 0.284076,  0.447183, 0, 0.632797, 0.582726, 0.229339, 0.425452, 0.0392362, 0,  0.253737, 0.554082, 0.633624, 0.447179, 0.331193, 0, 0.153644,  0.539335, 0.23805, 0.463906, 0.904408, 0, 0, 0.973178, 0.611544,  0.313084, 0.759866, 0.30788, 0, 0.673053, 0.549363, 0.47579,  0.860697, 0.0402561, 0, 0.966637, 0.24645, 0.435245, 0.0010199,  0.7129, 0, 0.692368, 0.801622, 0.553841, 0.381707, 0.538724, 0, 0,  0.262287, 0.315791, 0.917801, 0.634316, 0.289108, 0, 0.704247,  0.604718, 0.87445, 0.981229, 0.0311946, 0, 0.0553544, 0.39866,  0.120532, 0.990939, 0.0887175, 0, 0.15221, 0.685286, 0.989919,  0.375817, 0.459842, 0}, {0.883665, 0.436078, 0.99411}, {0.921118,  0.621378, 0.120286, 0.0763085, 0.286802, 0.33227, 0.416039,  0.471591, 0.412352, 0.351041, 0.384844, 0.416236, 0.0136913,  0.230509, 0.393906}, {0.327519, 0.861481, 0.545223, 0.403987,  0.951702}, {{1, 1, 0}, {0, 2, 0}, {1, 1, 0}, {0, 2, 2}, {1, 0,  2}, {1, 1, 2}, {1, 1, 3}, {2, 2, 4}}, 0.40164, 0.661558, 0.96791,  0.957592}, {-2.23048, -1.84665, -2.04043}}, {{{0, 0.480522,  0.04018, 0.847623, 0.881283, 0.19372, 0, 0.70791, 0.431584,  0.409693, 0.781368, 0.35687, 0, 0.04674, 0.993456, 0.767677,  0.126361, 0.652834, 0, 0.665938, 0.906196, 0.581138, 0.248847,  0.714236, 0, 0, 0.504556, 0.91958, 0.280937, 0.756644, 0.0240342,  0, 0.8794, 0.433314, 0.875361, 0.830314, 0.171489, 0, 0.00172982,  0.465668, 0.0489455, 0.81462, 0.95499, 0, 0.472212, 0.281268,  0.688259, 0.302156, 0.806274, 0, 0, 0.375073, 0.107121, 0.0533085,  0.0920381, 0.870516, 0, 0.187541, 0.772371, 0.335394, 0.846482,  0.308142, 0, 0.339057, 0.460033, 0.0161683, 0.136652, 0.337327, 0,  0.994365, 0.967223, 0.322032, 0.382337, 0.522153, 0, 0, 0.685955,  0.633773, 0.0801817, 0.715879, 0.310882, 0, 0.526652, 0.0268732,  0.623841, 0.440366, 0.33911, 0, 0.254502, 0.288447, 0.593883,  0.0309687, 0.915445, 0, 0.828414, 0.577715, 0.894317, 0.578118,  0.834049, 0}, {0.610492, 0.572284, 0.195781}, {0.311896, 0.924538,  0.938511, 0.115599, 0.596017, 0.613655, 0.41186, 0.0887261,  0.972175, 0.17329, 0.0727494, 0.834224, 0.683728, 0.579407,  0.0417807}, {0.918779, 0.855314, 0.00169178, 0.147464,  0.34066}, {{1, 2, 3}, {2, 0, 2}, {2, 1, 2}, {2, 2, 0}, {0, 1,  1}, {2, 2, 1}, {2, 0, 1}, {0, 2, 0}}, 0.0212649, 0.3912, 0.57518,  0.144879}, {-1.68177, -0.647663,  17.9692}}, {{{0, 0.709369, 0.466662, 0.636668, 0.0292801, 0.113353,  0, 0.853007, 0.224809, 0.940554, 0.141177, 0.679717, 0, 0.152059,  0.10633, 0.457449, 0.10031, 0.110279, 0, 0.187551, 0.602135,  0.0986183, 0.962815, 0.846891, 0, 0, 0.58087, 0.707419, 0.387635,  0.702011, 0.871501, 0, 0.240756, 0.750966, 0.672731, 0.758149,  0.38775, 0, 0.526158, 0.732177, 0.616971, 0.708033, 0.374098, 0,  0.625847, 0.159522, 0.607723, 0.26382, 0.438296, 0, 0, 0.557387,  0.509104, 0.301005, 0.591405, 0.976517, 0, 0.801686, 0.91337,  0.889394, 0.105015, 0.560929, 0, 0.162404, 0.216663, 0.346867,  0.17318, 0.636246, 0, 0.484485, 0.729896, 0.465147, 0.262148,  0.858638, 0, 0, 0.570373, 0.857424, 0.998328, 0.420342, 0.0129866,  0, 0.34832, 0.697323, 0.828936, 0.0364701, 0.546634, 0, 0.783952,  0.939542, 0.931455, 0.985705, 0.621548, 0, 0.72288, 0.584588,  0.812525, 0.985302, 0.238394, 0}, {0.854692, 0.347378,  0.723154}, {0.379756, 0.284319, 0.489954, 0.724826, 0.959415,  0.271332, 0.141634, 0.0275034, 0.130478, 0.234862, 0.595001,  0.243551, 0.190936, 0.303408, 0.609296}, {0.622003, 0.468056,  0.71882, 0.796771,  0.636701}, {{1, 0, 0}, {0, 2, 0}, {1, 2, 1}, {3, 1, 2}, {0, 1,  1}, {0, 2, 3}, {3, 1, 0}, {2, 1, 3}}, 0.229662, 0.864127,  0.449393, 0.913547}, {-2.07, -0.81294, -2.03472}}};

  for (unsigned int i = 0; i < sizeof (data) / sizeof (data[0]); ++i)
    {
      double dalpha[4*5*5];
      double dlogbeta[3];
      NormalDistribution prior_alpha = 
        normal_distribution (data[i].inputs.alphamean, 
                             data[i].inputs.alphastddev);
      NormalDistribution prior_logbeta = 
        normal_distribution (data[i].inputs.logbetamean, 
                             data[i].inputs.logbetastddev);

      memset (dlogbeta, lrand48 (), 3 * sizeof (dlogbeta[0]));

      for (unsigned int j = 0; j < 4; ++j)
        {
          for (unsigned int k = 0; k < 5; ++k)
            {
              data[i].inputs.alpha[j * 5 * 5 + k * 5 + k] = drand48 ();
            }
        }

      dqfunc (dalpha,
              dlogbeta,
              data[i].inputs.alpha,
              4,
              5,
              data[i].inputs.logbeta,
              3,
              data[i].inputs.pz,
              data[i].inputs.ratings,
              8,
              &prior_alpha.base,
              &prior_logbeta.base,
              1);

      for (unsigned int j = 0; j < 3; ++j)
        {
          assert (fabs (dlogbeta[j] - data[i].desired_output[j]) <=
                  1e-5 * (1 + fabs (dlogbeta[j]) + fabs (data[i].desired_output[j])) ||
                  ( fprintf (stderr, "%u %u: %g ?= %g\n", i, j, dlogbeta[j], data[i].desired_output[j]),
                    0 ));
        }
    }
}

int 
main (void) 
{
  test_logprating ();
  test_dlogpratingdalpha ();
  test_dlogpratingdlogbeta ();
  test_normaldistribution ();
  test_qfunc ();
  test_qfunc_symmetric ();
  test_dqfuncdalpha ();
  test_dqfuncdalpha_symmetric ();
  test_dqfuncdlogbeta ();
  test_dqfuncdlogbeta_symmetric ();

  return 0;
}
